package controllers

import (
	"github.com/gin-gonic/gin"
)

/*
 +----------------------------------------------------------------------
 + Title        : MsgController
 + Author       : huwl
 + Version      : 2.0.0
 + Initial-Time : 2020-11-23
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : DTM 二阶段 分布式事务控制层: 二阶段消息能够大幅降低消息最终一致性解决方案的难度
 +					已获得广泛的应用,下面是两个典型的应用。
 +						秒杀系统，该架构下单机可以轻松扛住上万个订单请求,并且保证库存数量和订单数量准确匹配
 +						缓存一致性 通过二阶段消息,可以轻松保证DB与缓存的一致性,大大优于队列或订阅binlog的方案
 +
 + SUCCESS      : 表示成功
 + FAILURE      : 表示失败，这个失败是指确定的失败结果，不需要重试。
                  例如子事务因转账余额不足而失败，dtm服务因为事务已完成不允许再次提交等
 + ONGOING      : 表示未完成，还在正常进行中，此时dtm服务器需要采用固定间隔重试，而不是指数退避算法重试
				  对tcc不管用,在tcc模式下和FAILURE状态一样

 + other status : 表示临时错误，采用指数退避算法重试，避免出现故障或者bug，导致大量重试，导致负载过高
 + SUCCESS http : 状态码 200； grpc： err == nil
 + FAILURE http : 状态码 409 (http.StatusConflict)；grpc Code == Aborted tcc 失败、未完成的状态必须使用409、425
 + ONGOING http : 状态码 425 (http.StatusTooEarly)；grpc Code == FailedPrecondition tcc 失败、未完成的状态必须使用409、425
 +----------------------------------------------------------------------
*/
type MsgController struct {
	BaseController
}

/**
 * 二阶段消息 http 方式
 * 总结子事务返回状态: FAILURE、ONGOING 则整个事务状态为 submitted 进行重试操作
 * @return Json
 * @author huwl
 */
// func (control MsgController) MsgHttp(ctx *gin.Context) {
// 	req := &ReqHTTP{
// 		Amount: 30,
// 		// TransInResult: "FAILURE",
// 		TransInResult: "ONGOING",
// 	}

// 	msg := dtmcli.NewMsg(tools.DtmHttpServer, shortuuid.New()).
// 		Add(tools.HttpServiceUrl+"/msg/transOut", req).
// 		Add(tools.HttpServiceUrl+"/msg/transIn", req)
// 	err := msg.Prepare(tools.HttpServiceUrl + "/msg/queryPrepared")
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	control.BaseSuccess(ctx, control.WithData(gin.H{
// 		"gid": msg.Gid,
// 	}))
// }

/**
 * 二阶段消息 do and commit http 方式
 *
 * @return Json
 * @author huwl
 */
// func (control MsgController) MsgDoAndCommitHttp(ctx *gin.Context) {
// 	req := &ReqHTTP{
// 		Amount: 30,
// 		// TransInResult: "FAILURE",
// 		TransInResult: "ONGOING",
// 	}

// 	gid := shortuuid.New()

// 	msg := dtmcli.NewMsg(tools.DtmHttpServer, gid).
// 		Add(tools.HttpServiceUrl+"/msg/transIn", req)

// 	db, err := tools.DatabaseManager.DB()
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}
// 	err = msg.DoAndSubmitDB(tools.HttpServiceUrl+"/queryPreparedB", db, func(tx *sql.Tx) error {
// 		// 执行表数据操作
// 		return nil
// 	})
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	control.BaseSuccess(ctx, control.WithData(gin.H{
// 		"gid": msg.Gid,
// 	}))
// }

/**
 * 二阶段消息 grpc 方式
 * 总结子事务返回状态: FAILURE、ONGOING 则整个事务状态为 submitted 进行重试操作
 * @return Json
 * @author huwl
 */
// func (control MsgController) MsgGrpc(ctx *gin.Context) {
// 	amount, _ := strconv.Atoi(ctx.DefaultQuery("amount", "30"))
// 	transInResult := ctx.DefaultQuery("trans_in_result", "")
// 	transOutResult := ctx.DefaultQuery("trans_out_result", "")
// 	req := &pbDemo.ReqGrpc{
// 		Amount:         int64(amount),
// 		TransInResult:  transInResult,
// 		TransOutResult: transOutResult,
// 		// 表示失败，这个失败是指确定的失败结果，不需要重试。
// 		// TransInResult: "FAILURE",
// 		// 表示未完成，还在正常进行中，此时dtm服务器需要采用固定间隔重试，而不是指数退避算法重试
// 		// TransInResult: "ONGOING",
// 	}

// 	// 获取微服务地址
// 	target, err := tools.GetServiceAddress(tools.ServiceName)
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	msg := dtmgrpc.NewMsgGrpc(tools.DtmGrpcServer, shortuuid.New()).
// 		Add(target+"/demo.DemoSrv/TransOut", req).
// 		Add(target+"/demo.DemoSrv/TransIn", req)

// 	err = msg.Submit()
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	control.BaseSuccess(ctx, control.WithData(gin.H{
// 		"gid": msg.Gid,
// 	}))
// }

/**
 * 预处理查询
 *
 * @return Json
 * @author huwl
 */
func (control MsgController) QueryPrepared(ctx *gin.Context) {}

/**
 * 预处理查询
 *
 * @return Json
 * @author huwl
 */
// func (control MsgController) QueryPreparedB(ctx *gin.Context) {
// 	gid := ctx.DefaultPostForm("gid", "")
// 	fmt.Println("gid =", gid)
// 	bb, err := dtmcli.BarrierFromQuery(ctx.Request.URL.Query())
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	db, err := tools.DatabaseManager.DB()
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	err = bb.QueryPrepared(db)
// 	if err != nil {
// 		control.BaseError(ctx, control.WithMessage(err.Error()))
// 		return
// 	}

// 	control.BaseSuccess(ctx, control.WithData(""))
// }
